// =============================================================================
//                           COPYRIGHT NOTICE
// Copyright 2000-2012 (c) Lattice Semiconductor Corporation
// ALL RIGHTS RESERVED
// This confidential and proprietary software may be used only as authorised by
// a licensing agreement from Lattice Semiconductor Corporation.
// The entire notice above must be reproduced on all authorized copies and
// copies may only be made to the extent permitted by a licensing agreement from
// Lattice Semiconductor Corporation.
//
// Lattice Semiconductor Corporation        TEL : 1-800-Lattice (USA and Canada)
// 5555 NE Moore Court                      408-826-6000 (other locations)
// Hillsboro, OR 97124                      web  : http://www.latticesemi.com/
// U.S.A                                    email: techsupport@latticesemi.com
// =============================================================================
//                FILE DETAILS
// Project          : scaler
// File             : scaler_tb.v
// Title            : top level testbench for the scaler.
// Description      : 
// =============================================================================
//                REVISION HISTORY
// Version          : 2.1
// Author(s)        : 
// Mod. Date        : May, 2012
// Changes Made     : Initial Creation
// -----------------------------------------------------------------------------

//====================timescale define
`ifdef TIMING_SIM
   `timescale 1ns/1ps
`else
   `timescale 1ns/100ps
`endif

`define TDF 1

module Scaler_tb;
// =============================================================================
// parameters define
// =============================================================================
`include "params.v"

localparam HC           = 10; //half clock period
localparam PHC          = 50;
localparam RUNTIME      = (10*3*MAX_TOTAL);
localparam WAITTIME     = 50;

localparam PLANEWIDTH   = (NUM_PLANE==1) ? 1 : clog2(NUM_PLANE-1);
localparam TI_WIDTH     = clog2(TOTAL_INPUT)+1;
localparam TO_WIDTH     = clog2(TOTAL_OUTPUT)+1;
localparam OXWIDTH      = clog2(VOUTWIDTH-1);
localparam OYWIDTH      = clog2(VOUTHEIGHT-1);
localparam NUM_PIXEL    = VINHEIGHT*VINWIDTH;
localparam OUT_PIXEL    = VOUTHEIGHT*VOUTWIDTH;
localparam PIXEL_INW    = clog2(NUM_PIXEL-1);
localparam PIXEL_OUTW   = clog2(OUT_PIXEL-1);
localparam NUMFWIDTH    = (NUM_FRAME==1) ? 1 : clog2(NUM_FRAME-1);
localparam IPWIDTH      = (PARALLEL=="FALSE") ? DWIDTH : ((YCBCR422=="TRUE") ? 2*DWIDTH : NUM_PLANE*DWIDTH);
localparam OPWIDTH      = (PARALLEL=="FALSE") ? DOUTWIDTH : ((YCBCR422=="TRUE") ? 2*DOUTWIDTH : NUM_PLANE*DOUTWIDTH);
localparam PARL_PLANE   = (PARALLEL=="FALSE") ? 1 : ((YCBCR422=="TRUE") ? 2 : NUM_PLANE); // actual planes of parallel processing
localparam SRAL_PLANE   = (PARALLEL== "TRUE") ? 1 : ((YCBCR422=="TRUE") ? 2 : NUM_PLANE); // actual planes of serial processing
localparam HBLANK       = 16;
localparam VBLANK       = 20;
localparam FRMWIDTH_ADDR   = 0,
	        FRMHEIGHT_ADDR  = 4,
	        OUTWIDTH_ADDR   = 8,
	        OUTHEIGHT_ADDR  = 12,
	        VSFACTOR_ADDR   = 16,
	        HSFACTOR_ADDR   = 20,
	        UPDATE_ADDR     = 24;

// =============================================================================
// internal signal define
// =============================================================================
reg                     rstn;
reg                     clk;
reg                     ce;
reg                     sr;
reg                     frmsync_in;
reg                     dvalid_in;
reg  [IPWIDTH-1:0]      din;
reg                     dout_enable;
wire                    pclk;
reg                     pwrite;
reg  [PADDRWIDTH-1:0]   paddr;
reg  [PBUSWIDTH-1:0]    pwdat;
wire [PBUSWIDTH-1:0]    prdat;

wire                    ready;
wire                    frm_resync;
wire [OPWIDTH-1:0]      dout;
wire                    frmsync_out;
wire                    dvalid_out;
wire [OXWIDTH-1:0]      fwidth_out;
wire [OYWIDTH-1:0]      fheight_out;

// =============================================================================
// Core top level instantiations
// =============================================================================
Scaler_top u1_Scaler_top(
               .clk(clk),
               .rstn(rstn),
               .frmsync_in(frmsync_in),
               .dvalid_in(dvalid_in),
               .din(din),
               .ready(ready),
               .pclk(pclk),
               .pwrite(pwrite),
               .paddr(paddr),
               .pwdat(pwdat),
               .prdat(prdat),
               .dout_enable(dout_enable),
               .frmsync_out(frmsync_out),
               .dvalid_out(dvalid_out),
               .dout(dout)
            );


function [31:0] clog2;
   input [31:0] value;
   for (clog2=0; value>0; clog2=clog2+1) value = value>>1;
endfunction             
//memory definition
reg  [DWIDTH-1:0]       mem_din  [NUM_PLANE-1:0][VINHEIGHT*VINWIDTH-1:0];
reg  [DOUTWIDTH-1:0]    mem_dout [NUM_PLANE-1:0][VOUTHEIGHT*VOUTWIDTH-1:0];
//internal signals definition
reg  [TI_WIDTH-1:0]     din_cnt;
reg  [TO_WIDTH-1:0]     dout_cnt;
reg  [PLANEWIDTH-1:0]   plane_in;
reg  [PLANEWIDTH-1:0]   plane_out;
reg  [31:0]             error_cnt;
reg  [31:0]             doutv_cnt;
reg                     ready_en;
reg                     run_en;
reg                     comp_error;
reg                     complete;
reg  [31:0]             seed;
reg  [1:0]              frame_in;
reg  [1:0]              frame_out;
reg  [PIXEL_INW-1:0]    pixel_in;
reg  [PIXEL_OUTW-1:0]   pixel_out;
reg  [PIXEL_INW+1:0]    frm_pixels[NUM_FRAME-1:0];
reg  [PIXEL_OUTW+1:0]   out_pixels[NUM_FRAME-1:0];
reg                     sync_error;
reg  [31:0]             vsfactors[2:0];
reg  [31:0]             hsfactors[2:0];
reg  [31:0]             frmwidths[2:0];
reg  [31:0]             frmheights[2:0];
reg  [31:0]             outwidths[2:0];
reg  [31:0]             outheights[2:0];
reg                     compare_en;
reg                     checked;
reg                     clk_p;

wire [OPWIDTH-1:0]      ref_dout;
wire [IPWIDTH-1:0]      dinw;
integer                 fh_sti;
integer                 fh_gld;
integer                 num_sti;
integer                 num_gld;
genvar kk;


//===input pixels stat.
always @(posedge clk or negedge rstn)
begin
   if(!rstn) begin
      plane_in <= {PLANEWIDTH{1'b0}};
   end else if(ce) begin
      if(sr) begin
         plane_in <= {PLANEWIDTH{1'b0}};
      end else if(ready_en && run_en && ready) begin
         if(plane_in == (SRAL_PLANE-1)) begin
            plane_in <= {PLANEWIDTH{1'b0}};
         end else begin
            plane_in <= plane_in + 1;
         end
      end
   end
end
always @(posedge clk or negedge rstn)
begin
   if(!rstn) begin
      frame_in <= {NUMFWIDTH{1'b0}};
   end else if(ce) begin
      if(sr) begin
         frame_in <= {NUMFWIDTH{1'b0}};
      end else if (ready_en && run_en && ready && (pixel_in == (frm_pixels[frame_in]-1)) && (plane_in==SRAL_PLANE-1)) begin
         if (frame_in == (NUM_FRAME-1)) begin
            frame_in <= {NUMFWIDTH{1'b0}};
         end else begin
            frame_in <= frame_in + 1;
         end
      end
   end
end
always @(posedge clk or negedge rstn)
begin
   if(!rstn) begin
      pixel_in <= {PIXEL_INW{1'b0}};
   end else if(ce) begin
      if(sr)  begin
         pixel_in <= {PIXEL_INW{1'b0}};
      end else if (ready_en && run_en && ready && (plane_in==SRAL_PLANE-1)) begin
         if (pixel_in == (frm_pixels[frame_in]-1)) begin
            pixel_in <= {PIXEL_INW{1'b0}};
         end else begin
            pixel_in <= pixel_in + 1;
         end
      end
   end
end
always @(posedge clk or negedge rstn)
begin
   if(!rstn) begin
      din_cnt <= {TI_WIDTH{1'b0}};
   end else if(ce) begin
      if(sr)  begin
         din_cnt <= {TI_WIDTH{1'b0}};
      end else if (ready_en && run_en && ready) begin
         din_cnt <= din_cnt + 1;
      end
   end
end

//-----output pixels stat.
always @(posedge clk or negedge rstn)
begin
   if(!rstn) begin
      plane_out <= {PLANEWIDTH{1'b0}};
   end else if(ce) begin
      if(sr) begin
         plane_out <= {PLANEWIDTH{1'b0}};
      end else if(dvalid_out) begin
         if(plane_out == (SRAL_PLANE-1)) begin
            plane_out <= {PLANEWIDTH{1'b0}};
         end else begin
            plane_out <= plane_out + 1;
         end
      end
   end
end
always @(posedge clk or negedge rstn)
begin
   if(!rstn) begin
      frame_out <= {NUMFWIDTH{1'b0}};
   end else if(ce) begin
      if(sr) begin
         frame_out <= {NUMFWIDTH{1'b0}};
      end else if(dvalid_out && (pixel_out == (out_pixels[frame_out]-1)) && (plane_out==SRAL_PLANE-1)) begin
         if(frame_out == (NUM_FRAME-1)) begin
            frame_out <= {NUMFWIDTH{1'b0}};
         end else begin
            frame_out <= frame_out + 1;
         end
      end
   end
end
always @(posedge clk or negedge rstn)
begin
   if(!rstn) begin
      pixel_out <= {PIXEL_OUTW{1'b0}};
   end else if(ce) begin
      if(sr) begin
         pixel_out <= {PIXEL_OUTW{1'b0}};
      end else if (dvalid_out && (plane_out==SRAL_PLANE-1)) begin
         if(pixel_out == (out_pixels[frame_out]-1)) begin
            pixel_out <= {PIXEL_OUTW{1'b0}};
         end else begin
            pixel_out <= pixel_out + 1;
         end
      end
   end
end
always @(posedge clk or negedge rstn)
begin
   if(!rstn) begin
      doutv_cnt <= {31{1'b0}};
   end else if(ce) begin
      if(sr) begin
         doutv_cnt <= {31{1'b0}};
      end else if(dvalid_out == 1'b1) begin
         doutv_cnt <= doutv_cnt + 1;
      end
   end
end
generate
if(PARALLEL=="TRUE") begin
   for(kk=0;kk<PARL_PLANE;kk=kk+1) begin
      assign dinw    [(kk+1)*DWIDTH-1:kk*DWIDTH] = mem_din[kk][pixel_in];
      assign ref_dout[(kk+1)*DOUTWIDTH-1:kk*DOUTWIDTH] = mem_dout[kk][pixel_out];
   end
end else begin
   assign dinw     = mem_din[plane_in][pixel_in];
   assign ref_dout = mem_dout[plane_out][pixel_out];
end
endgenerate

//-----input control logic
always @(posedge clk or negedge rstn)
begin
   if(!rstn) begin
      din         <= #`TDF {DWIDTH{1'b0}};
      dvalid_in   <= #`TDF 1'b0;
      frmsync_in  <= #`TDF 1'b0;
   end else if(ce) begin
      if(sr) begin
         din         <= #`TDF {DWIDTH{1'b0}};
         dvalid_in   <= #`TDF 1'b0;
         frmsync_in  <= #`TDF 1'b0;
      end else if (ready && ready_en && run_en) begin
         din         <= #`TDF dinw;
         dvalid_in   <= #`TDF 1'b1;
         frmsync_in  <= #`TDF (pixel_in==0 && plane_in==0) ? 1'b1 : 1'b0;
      end else begin
         //din         <= #`TDF {DWIDTH{1'b0}};
         dvalid_in   <= #`TDF 1'b0;
         frmsync_in  <= #`TDF 1'b0;
      end
   end
end
//-----outpu data check logic
always @(posedge clk or negedge rstn)
begin
   if(!rstn) begin
      comp_error <= 1'b0;
      error_cnt  <= {32{1'b0}};
   end else if(ce) begin
      if(sr) begin
         comp_error <= 1'b0;
         error_cnt  <= {32{1'b0}};
      end else if(dvalid_out==1'b1) begin
         if(compare_en==1'b1) begin
            if(dout !== ref_dout) begin
               $display("ERROR! Actual data = %h   Expect data = %h   At time %d", dout, ref_dout, $time);
               error_cnt  <= error_cnt + 1;
               comp_error <= 1'b1;
            end else begin
               comp_error <= 1'b0;
            end
         end
         dout_cnt <= dout_cnt + 1;
      end else begin
         comp_error <= 1'b0;
      end
   end
end
//-----frame sync signal check logic
always @(posedge clk or negedge rstn)
begin
   if(!rstn) begin
      sync_error <= 1'b0;
   end else if(ce) begin
      if(sr) begin
         sync_error <= 1'b0;
      end if(dvalid_out) begin
         if(pixel_out==0 && plane_out==0) begin
            if(!frmsync_out) begin
               sync_error <= 1'b1;
            end
         end else if(frmsync_out) begin
            sync_error <= 1'b1;
         end
      end else if(frmsync_out) begin
         sync_error <= 1'b1;
      end
   end
end
always @(posedge clk or negedge rstn)
begin
   if(!rstn) begin
      compare_en <= 1'b1;
   end else if(ce) begin
      if(sr) begin
         compare_en <= 1'b1;
      end else if(complete==0) begin
         if(dout_cnt >= TOTAL_OUTPUT-1) begin
            compare_en <= 1'b0;
            complete <= 1'b1;
         end
      end else begin
         compare_en <= 1'b0;
      end
   end
end
//-----clock generator
initial begin
   clk = 1'b0;
   forever #HC clk = ~clk;
end
initial begin
   clk_p = 1'b0;
   forever #PHC clk_p = ~clk_p;
end
assign pclk = ( SEPPCLK=="TRUE") ? clk_p : clk;


//-----stimulus the core
initial begin
   input_init;
   async_reset(2);
   sync_reset(2);
   delay(10);
   set_params(0);
   delay(10);
   fork
      input_data;
      update_params;
   join
   delay(WAITTIME);
end
initial begin
   fh_sti = $fopen("stimulus_Scaler.dat","rb");
   num_sti = 0;
   delay(10);
   while (complete == 0) begin
      wait(ready && ready_en && run_en && (pixel_in==0) && (plane_in==0) && (num_sti<NUM_FRAME)) begin
         # 1;
         read_frame_sti(num_sti);
         //$display(" Input frame %d", num_sti);
         num_sti = num_sti + 1;
         delay(10);
      end
      wait(pixel_in==VINWIDTH-1) begin
         delay(10);
      end
   end
end
initial begin
   fh_gld = $fopen("golden_Scaler.dat","rb");
   num_gld = 0;
   delay(10);
   while (complete == 0) begin
      wait(frmsync_out && (num_gld<NUM_FRAME)) begin
         # 1;
         read_frame_gld(num_gld);
         $display(" Output frame %d", num_gld);
         num_gld = num_gld + 1;
         delay(10);
      end
   end
end
//---get input data and output data
task read_frame_sti;
   input [31:0] sti;
   integer ii,jj,pixs,frm;
   reg   [15:0] tmp[NUM_PIXEL-1:0];
   reg   [15:0] pix;
   begin
      frm  = frm_pixels[sti];
      if(YCBCR422=="TRUE") begin
         // Y plane
         pixs = $fread(tmp,fh_sti,,frm);
         for(jj=0;jj<frm;jj=jj+1) begin
            pix = {tmp[jj][7:0],tmp[jj][15:8]};
            mem_din[1][jj] = pix[DWIDTH-1:0];
         end
         // Cb & Cr planes
         pixs = $fread(tmp,fh_sti,,frm);
         for(jj=0;jj<frm;jj=jj+1) begin
            pix = {tmp[jj][7:0],tmp[jj][15:8]};
            if(jj<(frm/2)) begin
               mem_din[0][jj*2] = pix[DWIDTH-1:0];
            end else begin
               mem_din[0][(jj-(frm/2))*2+1] = pix[DWIDTH-1:0];
            end
         end
      end else begin
         for(ii=0;ii<NUM_PLANE;ii=ii+1) begin
            pixs = $fread(tmp,fh_sti,,frm);
            for(jj=0;jj<frm;jj=jj+1) begin
               pix = {tmp[jj][7:0],tmp[jj][15:8]};
               mem_din[NUM_PLANE-1-ii][jj] = pix[DWIDTH-1:0];
            end
         end
      end
   end
endtask
task read_frame_gld;
   input [31:0]  gld;
   integer ii,jj,frm,pixs;
   reg   [15:0] tmp[OUT_PIXEL-1:0];
   reg   [15:0] pix;
   begin
      frm = out_pixels[gld];
      if(YCBCR422=="TRUE") begin
         // Y plane
         pixs = $fread(tmp,fh_gld,,frm);
         for(jj=0;jj<frm;jj=jj+1) begin
            pix = {tmp[jj][7:0],tmp[jj][15:8]};
            mem_dout[1][jj] = pix[DOUTWIDTH-1:0];
         end
         // Cb & Cr planes
         pixs = $fread(tmp,fh_gld,,frm);
         for(jj=0;jj<frm;jj=jj+1) begin
            pix = {tmp[jj][7:0],tmp[jj][15:8]};
            if(jj<(frm/2)) begin
               mem_dout[0][jj*2] = pix[DOUTWIDTH-1:0];
            end else begin
               mem_dout[0][(jj-(frm/2))*2+1] = pix[DOUTWIDTH-1:0];
            end
         end
      end else begin
         for(ii=0;ii<NUM_PLANE;ii=ii+1) begin
            pixs = $fread(tmp,fh_gld,,frm);
            for(jj=0;jj<frm;jj=jj+1) begin
               pix = {tmp[jj][7:0],tmp[jj][15:8]};
               mem_dout[NUM_PLANE-1-ii][jj] = pix[DOUTWIDTH-1:0];
            end
         end
      end
   end
endtask

//-----rand interval control
initial begin
   while(complete == 1'b0) begin
      wait(ready == 1'b1 && run_en == 1'b1) begin
         //randdelay(6);
         ready_en = 1'b1;
         delay(1);
         ready_en = 1'b0;
      end
   end
end
//-----final check
initial begin
   checked = 0;
   wait(complete == 1) begin
      $fclose(fh_sti);
      $fclose(fh_gld);
      check_result;
      checked = 1;
   end
   delay(WAITTIME);
   $stop;
end
//-----force complete
initial begin
   delay(RUNTIME+500);
   if(checked == 0) begin
      check_result;
      $stop;
   end
end

//---variables initial task
task input_init;
   integer ii;
   begin
      rstn        = 1'b0;
      sr          = 1'b0;
      ce          = 1'b1;
      dvalid_in   = 1'b0;
      din         = 0;
      complete    = 1'b0;
      error_cnt   = 0;
      ready_en    = 0;
      run_en      = 0;
      paddr       = 0;
      pwdat       = 0;
      pwrite      = 1'b0;
      seed        = SEED;
      dout_enable = 1'b1;
      cnt_reset;
      mem_zero;
      if(DYNAMIC=="TRUE") begin
         frmwidths[0]   = FRMWIDTH_0;
         frmwidths[1]   = FRMWIDTH_1;
         frmwidths[2]   = FRMWIDTH_2;
         frmheights[0]  = FRMHEIGHT_0;
         frmheights[1]  = FRMHEIGHT_1;
         frmheights[2]  = FRMHEIGHT_2;
         outwidths[0]   = OUTWIDTH_0;
         outwidths[1]   = OUTWIDTH_1;
         outwidths[2]   = OUTWIDTH_2;
         outheights[0]  = OUTHEIGHT_0;
         outheights[1]  = OUTHEIGHT_1;
         outheights[2]  = OUTHEIGHT_2;
      end else begin
         for(ii=0;ii<NUM_FRAME;ii=ii+1) begin
            frmwidths[ii]  = VINWIDTH-1;
            frmheights[ii] = VINHEIGHT-1;
            outwidths[ii]  = VOUTWIDTH-1;
            outheights[ii] = VOUTHEIGHT-1;
         end
      end
      for(ii=0;ii<NUM_FRAME;ii=ii+1) begin
         frm_pixels[ii] =  (frmwidths[ii]+1)*(frmheights[ii]+1);
         out_pixels[ii] =  (outwidths[ii]+1)*(outheights[ii]+1);
      end
      if(DYNAMIC=="TRUE") begin
         for(ii=0;ii<NUM_FRAME;ii=ii+1) begin
            vsfactors[ii]   = ((frmheights[ii]+1)*(1<<VFCBPWIDTH))/(outheights[ii]+1);
            hsfactors[ii]   = ((frmwidths[ii]+1)*(1<<HFCBPWIDTH))/(outwidths[ii]+1);
         end
      end else begin
         for(ii=0;ii<NUM_FRAME;ii=ii+1) begin
            vsfactors[ii]   = VSFACTOR;
            hsfactors[ii]   = HSFACTOR;
         end
      end
   end
endtask
task params_write;
   input [31:0] addr;
   input [31:0] wdat;
   begin
      wait(ce);
      pwrite = 1'b1;
      paddr  = addr;
      pwdat  = wdat;
      @ (posedge pclk);
      # 1;
      pwrite = 1'b0;
      paddr  = 0;
      pwdat  = 0;
   end
endtask
task params_read;
   input [31:0] addr;
   begin
      pwrite = 1'b0;
      paddr  = addr;
      @ (posedge pclk);
      # 1;
      pwrite = 1'b0;
      paddr  = 0;
   end
endtask
task cnt_reset;
   begin
      dout_cnt = 0;
   end
endtask
task mem_zero;
   integer i,j,k;
   begin
      for(j=0;j<NUM_PLANE;j=j+1) begin
         for(k=0;k<=NUM_PIXEL;k=k+1)
            mem_din[j][k] = 0;
         for(k=0;k<=VOUTHEIGHT*VOUTWIDTH;k=k+1)
            mem_dout[j][k] = 0;
      end
   end
endtask

//---final check task
task check_result;
   begin
      if(doutv_cnt == 0) begin
         $display("");
         $display("<><><><><><><><><><><><");
         $display("   No valid output data!");
         $display("<><><><><><><><><><><><");
         $display("");
      end else if(error_cnt == 0 && sync_error==0) begin
         if(doutv_cnt < (TOTAL_OUTPUT-1)) begin
            $display("");
            $display("<><><><><><><>><><><><><><><><><");
            $display("  Output data is insufficient!");
            $display("<><><><><><><>><><><><><><><><><");
            $display("dout cnt is %d\n",doutv_cnt);
         end else begin
            $display("");
            $display("=======================");
            $display("   Simulation passed!");
            $display("=======================");
            $display("");
         end
      end else begin
         if(error_cnt>0) begin
            $display("");
            $display("<><><><><><><><><><><><");
            $display("   Simulation failed!");
            $display("<><><><><><><><><><><><");
            $display("");
            if(doutv_cnt < (TOTAL_OUTPUT-1)) begin
               $display("dout cnt is %d\n",doutv_cnt);
               $display("");
            end
         end else if(sync_error==1) begin
            $display("");
            $display("<><><><><><><><><><><><><><><>");
            $display("   Frame sync checking failed!");
            $display("<><><><><><><><><><><><><><><>");
            $display("");
         end
      end
   end
endtask

//---params set task
task set_params;
   input integer nump;
   begin
      paddr=UPDATE_ADDR   ;
      delay(5);
      if(PBUSWIDTH==32) begin
         if(DYNAMIC=="TRUE") begin
            params_write(FRMWIDTH_ADDR,  frmwidths[nump]);
            params_write(FRMHEIGHT_ADDR, frmheights[nump]);
            params_write(OUTWIDTH_ADDR,  outwidths[nump]);
            params_write(OUTHEIGHT_ADDR, outheights[nump]);
            if(KERNEL=="NEAREST") begin
               params_write(VSFACTOR_ADDR,  vsfactors[nump]);
               params_write(HSFACTOR_ADDR,  hsfactors[nump]);
            end
            params_write(UPDATE_ADDR    ,1);
         end
      end else if(PBUSWIDTH==16) begin
         if(DYNAMIC=="TRUE") begin
            params_write(FRMWIDTH_ADDR,   frmwidths[nump][15: 0]);
            params_write(FRMWIDTH_ADDR+2, frmwidths[nump][31:16]);
            params_write(FRMHEIGHT_ADDR,  frmheights[nump][15: 0]);
            params_write(FRMHEIGHT_ADDR+2,frmheights[nump][31:16]);
            params_write(OUTWIDTH_ADDR,   outwidths[nump][15: 0]);
            params_write(OUTWIDTH_ADDR+2, outwidths[nump][31:16]);
            params_write(OUTHEIGHT_ADDR,  outheights[nump][15: 0]);
            params_write(OUTHEIGHT_ADDR+2,outheights[nump][31:16]);
            if(KERNEL=="NEAREST") begin
               params_write(VSFACTOR_ADDR,   vsfactors[nump][15: 0]);
               params_write(VSFACTOR_ADDR+2, vsfactors[nump][31:16]);
               params_write(HSFACTOR_ADDR,   hsfactors[nump][15: 0]);
               params_write(HSFACTOR_ADDR+2, hsfactors[nump][31:16]);
            end
            params_write(UPDATE_ADDR    ,1);
            params_write(UPDATE_ADDR+2  ,0);
         end
      end else if(PBUSWIDTH==8) begin
         if(DYNAMIC=="TRUE") begin
            params_write(FRMWIDTH_ADDR,   frmwidths[nump][ 7: 0]);
            params_write(FRMWIDTH_ADDR+1, frmwidths[nump][15: 8]);
            params_write(FRMWIDTH_ADDR+2, frmwidths[nump][23:16]);
            params_write(FRMWIDTH_ADDR+3, frmwidths[nump][31:24]);
            params_write(FRMHEIGHT_ADDR,  frmheights[nump][ 7: 0]);
            params_write(FRMHEIGHT_ADDR+1,frmheights[nump][15: 8]);
            params_write(FRMHEIGHT_ADDR+2,frmheights[nump][23:16]);
            params_write(FRMHEIGHT_ADDR+3,frmheights[nump][31:24]);
            params_write(OUTWIDTH_ADDR,   outwidths[nump][ 7: 0]);
            params_write(OUTWIDTH_ADDR+1, outwidths[nump][15: 8]);
            params_write(OUTWIDTH_ADDR+2, outwidths[nump][23:16]);
            params_write(OUTWIDTH_ADDR+3, outwidths[nump][31:24]);
            params_write(OUTHEIGHT_ADDR,  outheights[nump][ 7: 0]);
            params_write(OUTHEIGHT_ADDR+1,outheights[nump][15: 8]);
            params_write(OUTHEIGHT_ADDR+2,outheights[nump][23:16]);
            params_write(OUTHEIGHT_ADDR+3,outheights[nump][31:24]);
            if(KERNEL=="NEAREST") begin
               params_write(VSFACTOR_ADDR,   vsfactors[nump][ 7: 0]);
               params_write(VSFACTOR_ADDR+1, vsfactors[nump][15: 8]);
               params_write(VSFACTOR_ADDR+2, vsfactors[nump][23:16]);
               params_write(VSFACTOR_ADDR+3, vsfactors[nump][31:24]);
               params_write(HSFACTOR_ADDR,   hsfactors[nump][ 7: 0]);
               params_write(HSFACTOR_ADDR+1, hsfactors[nump][15: 8]);
               params_write(HSFACTOR_ADDR+2, hsfactors[nump][23:16]);
               params_write(HSFACTOR_ADDR+3, hsfactors[nump][31:24]);
            end
            params_write(UPDATE_ADDR    ,1);
            params_write(UPDATE_ADDR+1  ,0);
            params_write(UPDATE_ADDR+2  ,0);
            params_write(UPDATE_ADDR+3  ,0);
         end
      end
   end
endtask
task update_params;
   integer numf;
   begin
      delay(2);
      while(run_en == 1'b1) begin
         wait(dvalid_in && (pixel_in==(frm_pixels[frame_in]-32*3))) begin
            numf = (frame_in+1)%NUM_FRAME;
            delay(2);
            set_params(numf);
         end
         @ (posedge clk);
      end
      delay(2);
   end
endtask
//---input valid data task
task input_data;
   begin
      @ (posedge clk);
      # 1;
      run_en = 1'b1;
      while(run_en == 1'b1) begin
         wait(dvalid_out) begin
            if(dout_cnt >= TOTAL_OUTPUT-1) begin
               run_en     = 1'b0;
            end
            @ (posedge clk);
         end
      end
   end
endtask 

//---async reset task
task async_reset;
   input [31:0] dc;
   begin
      # 1 rstn = 1'b0;
      repeat (dc) @ (posedge clk);
      #HC rstn = 1'b1;
   end
endtask
//---sync reset task
task sync_reset;
   input [31:0] dc;
   begin
      # 1 sr = 1'b1;
      repeat (dc) @ (posedge clk);
      # 1 sr = 1'b0;
   end
endtask
//---delay task
task automatic delay;
   input [31:0] dc;
   begin
      repeat (dc) @ (posedge clk);
      # 1;
   end
endtask
//---random delay task
task automatic randdelay;
   input [31:0] dc;
   integer nc;
   begin
      nc   = {$random(seed)} % dc;
      repeat(nc) @ (posedge clk);
      # 1;
   end
endtask

GSR GSR_INST(.GSR(rstn));
PUR PUR_INST(.PUR(1'b1));
endmodule
